import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;


/**
 * Interface representing a relational algebra expression.
 * @author Jonathan
 *
 */
public interface RAExpression {
	
	/**
	 * Runs the relational algebra expression. Returns the name
	 * of the output file from running the expression.
	 * @throws IOException 
	 */
	public RAOutput execute() throws IOException;
	
	/**
	 * Pushes the select list of the RA Expression down as far as possible
	 * allowing maximum projecting along the way.
	 * @param referencedColumns
	 */
	public void pushdownReferencedColumnsList(ArrayList<Expression> referencedColumns);
	
	/**
	 * Accepts and runs the supplied visitor.
	 */
	public <T> T accept(RAExpressionVisitor<T> v, Object... args);

	/**
	 * Estimates the cost of executing this RAExpression.
	 * @param catalog 
	 * @param tempCatalog 
	 * @return
	 */
	public RAStatistics estimateCost(Map<String, TableData> catalog, Map<String, TableData> tempCatalog);

	/**
	 * Puts all of the tables in this RA expression into the provided map. The map maps correlations to
	 * table names.
	 * @param tables
	 */
	public void getTables(Map<String, String> tables);

	/**
	 * Generates all possible RA expressions that result from simple join transformations of the form
	 * (A JOIN (B JOIN C)) -> (C JOIN (B JOIN A)) and (A JOIN (B JOIN C)) -> (B JOIN (A JOIN C)).
	 * @return
	 */
	public ArrayList<RAExpression> getJoinTransformations();

	/**
	 * Returns true if this RAExpression is referenced in this Expression.
	 * @param e
	 * @return
	 */
	public boolean referencedByExpression(Expression e);
	
	/**
	 * Adds a disjunction to the where clause of this RAExpression.
	 * @param e
	 */
	public void addWhereDisjunction(Expression e);
	
	/**
	 * Prints the join plan.
	 * @return
	 */
	public String joinPlanToString();

	/**
	 * Modifies internal RAExpression state so that the RAExpression will evaluate the
	 * provided select list.
	 * @param select
	 */
	public void applySelectList(ArrayList<Expression> select);

	/**
	 * Pushes down join predicates through an RAJoin and all its subjoins.
	 * @param joinWhereClauses
	 */
	public void pushdownJoinPredicates(ArrayList<Expression> joinWhereClauses);
}
